package com.kerry.socket;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramChannel;
import io.netty.channel.socket.nio.NioDatagramChannel;

import java.net.InetSocketAddress;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class UDPServer {
	private static final Logger LOGGER = Logger.getLogger(UDPServer.class);
	
	@Value("${udpServer.port}")
	private Integer port;
	
	
	private Channel acceptorChannel;
	
	
	@Autowired
	private ServerUDPHandler udpHandler ;
	
	
	public UDPServer() {
	}

	private Channel createAcceptorChannel() {
		 Bootstrap serverBootstrap = new Bootstrap();
         serverBootstrap.group(new NioEventLoopGroup());
         serverBootstrap.channel(NioDatagramChannel.class);
         
		serverBootstrap.option(ChannelOption.SO_REUSEADDR, false)

		.handler(new ChannelInitializer<DatagramChannel>() {
			@Override
			protected void initChannel(final DatagramChannel ch)
					throws Exception {
				LOGGER.info("udp server is initChannel port:"+port);
				final ChannelPipeline pipeline = ch.pipeline();
				pipeline.addLast("handler", udpHandler);
			}
		});
		try {
			ChannelFuture channelFuture = serverBootstrap.bind(
					new InetSocketAddress(port)).sync();
			// channelFuture.channel().closeFuture().awaitUninterruptibly();//.awaitUninterruptibly();
			channelFuture.awaitUninterruptibly();
			if (channelFuture.isSuccess()) {
				return channelFuture.channel();
			} else {
				LOGGER.warn(String.format(
						"Failed to open socket! Cannot bind to port: %d!",
						port));
			}
		} catch (InterruptedException e) {
			LOGGER.error("Failed to create acceptor socket.", e);
		}
		return null;

	}

	public UDPServer(int port,ServerUDPHandler udpHandler) {
		this.port = port;
		this.udpHandler = udpHandler;
	}

	public void start() {
		acceptorChannel = createAcceptorChannel();
	}

	public void stop() {
		if (acceptorChannel != null)
			acceptorChannel.close().addListener(ChannelFutureListener.CLOSE);
	}

	public void restart() {
		stop();
		start();

	}

	public Integer getPort() {
		return port;
	}

	public void setPort(Integer port) {
		this.port = port;
	}

	public Channel getAcceptorChannel() {
		return acceptorChannel;
	}

	public void setAcceptorChannel(Channel acceptorChannel) {
		this.acceptorChannel = acceptorChannel;
	}

	public ServerUDPHandler getUdpHandler() {
		return udpHandler;
	}

	public void setUdpHandler(ServerUDPHandler udpHandler) {
		this.udpHandler = udpHandler;
	}
}
